package com.hunter.api.help;

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;

import com.alibaba.fastjson.JSONObject;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

/**
 * StringHelper
 * 字符串相关方法
 *
 * @author HunterHuang
 * @version 1.0
 * @date 2018/9/12 12:50
 */
public class StringHelper {

    /**
     * ASCII 码
     * ASCII 码，总共有 128 个，用一个字节的低 7 位表示，0~31 是控制字符如换行回车删除等；32~126 是打印字符，可以通过键盘输入并且能够显示出来。
     * ISO-8859-1
     * 128 个字符显然是不够用的，于是 ISO 组织在 ASCII 码基础上又制定了一些列标准用来扩展 ASCII 编码，它们是 ISO-8859-1~ISO-8859-15，其中 ISO-8859-1 涵盖了大多数西欧语言字符，所有应用的最广泛。ISO-8859-1 仍然是单字节编码，它总共能表示 256 个字符。
     * GB2312
     * 它的全称是《信息交换用汉字编码字符集 基本集》，它是双字节编码，总的编码范围是 A1-F7，其中从 A1-A9 是符号区，总共包含 682 个符号，从 B0-F7 是汉字区，包含 6763 个汉字。
     * GBK
     * 全称叫《汉字内码扩展规范》，是国家技术监督局为 windows95 所制定的新的汉字内码规范，它的出现是为了扩展 GB2312，加入更多的汉字，它的编码范围是 8140~FEFE（去掉 XX7F）总共有 23940 个码位，它能表示 21003 个汉字，它的编码是和 GB2312 兼容的，也就是说用 GB2312 编码的汉字可以用 GBK 来解码，并且不会有乱码。
     * GB18030
     * 全称是《信息交换用汉字编码字符集》，是我国的强制标准，它可能是单字节、双字节或者四字节编码，它的编码与 GB2312 编码兼容，这个虽然是国家标准，但是实际应用系统中使用的并不广泛。
     * UTF-16
     * 说到 UTF 必须要提到 Unicode（Universal code 统一码），ISO 试图想创建一个全新的超语言字典，世界上所有的语言都可以通过这本字典来相互翻译。可想而知这个字典是多么的复杂，关于 Unicode 的详细规范可以参考相应文档。Unicode 是 Java 和 XML 的基础，下面详细介绍 Unicode 在计算机中的存储形式。
     * UTF-16 具体定义了 Unicode 字符在计算机中存取方法。UTF-16 用两个字节来表示 Unicode 转化格式，这个是定长的表示方法，不论什么字符都可以用两个字节表示，两个字节是 16 个 bit，所以叫 UTF-16。UTF-16 表示字符非常方便，每两个字节表示一个字符，这个在字符串操作时就大大简化了操作，这也是 Java 以 UTF-16 作为内存的字符存储格式的一个很重要的原因。
     * UTF-8
     * UTF-16 统一采用两个字节表示一个字符，虽然在表示上非常简单方便，但是也有其缺点，有很大一部分字符用一个字节就可以表示的现在要两个字节表示，存储空间放大了一倍，在现在的网络带宽还非常有限的今天，这样会增大网络传输的流量，而且也没必要。而 UTF-8 采用了一种变长技术，每个编码区域有不同的字码长度。不同类型的字符可以是由 1~6 个字节组成。
     * UTF-8 有以下编码规则：
     * 如果一个字节，最高位（第 8 位）为 0，表示这是一个 ASCII 字符（00 - 7F）。可见，所有 ASCII 编码已经是 UTF-8 了。
     * 如果一个字节，以 11 开头，连续的 1 的个数暗示这个字符的字节数，例如：110xxxxx 代表它是双字节 UTF-8 字符的首字节。
     * 如果一个字节，以 10 开始，表示它不是首字节，需要向前查找才能得到当前字符的首字节
     *
     * @param stringData 要查找encode的字符串
     * @return 字符串编码的名称
     */
    public static String getEncode(String stringData) {
        String encode = "ASCII";
        if (Charset.forName(encode).newEncoder().canEncode(stringData)) {
            return encode;
        }
        encode = "ISO-8859-1";
        if (Charset.forName(encode).newEncoder().canEncode(stringData)) {
            return encode;
        }
        encode = "GB2312";
        if (Charset.forName(encode).newEncoder().canEncode(stringData)) {
            return encode;
        }
        encode = "GBK";
        if (Charset.forName(encode).newEncoder().canEncode(stringData)) {
            return encode;
        }
        encode = "GB18030";
        if (Charset.forName(encode).newEncoder().canEncode(stringData)) {
            return encode;
        }
        encode = "UTF-8";
        if (Charset.forName(encode).newEncoder().canEncode(stringData)) {
            return encode;
        }
        encode = "UTF-16";
        if (Charset.forName(encode).newEncoder().canEncode(stringData)) {
            return encode;
        }

        return "";
    }

    /**
     * 字符串转码
     *
     * @param stringData
     * @param newEncode
     * @return
     */
    public static String transCode(String stringData, String newEncode) {
        Charset current = Charset.forName(getEncode(stringData));
        if (newEncode.equals(getEncode(stringData))) {
            return stringData;
        }

        //编码
        byte[] bytes = stringData.getBytes(current);
        //解码:用什么字符集编码就用什么字符集解码
        return new String(bytes, Charset.forName(newEncode));
    }

    public static String transCode(String stringData) {
        return transCode(stringData, "UTF-8");
    }

    /**
     * 16进制字符串转换为字符串，默认编码格式："utf-8"，可能会有不可见字符！
     *
     * @param hexStr 16进制字符串
     * @return 转换后的字符串
     */
    public static String hexStr2Str(String hexStr) {
        return hexStr2Str(hexStr, "UTF-8");
    }

    /**
     * 16进制字符串转换为字符串
     *
     * @param charsetName 用于编码 String 的 Charset
     */
    public static String hexStr2Str(String hexStr, String charsetName) {
        hexStr = hexStr.toUpperCase();
        String str = "0123456789ABCDEF";
        char[] hexs = hexStr.toCharArray();
        byte[] bytes = new byte[hexStr.length() / 2];
        int n;

        for (int i = 0; i < bytes.length; i++) {
            n = str.indexOf(hexs[2 * i]) * 16;
            n += str.indexOf(hexs[2 * i + 1]);
            bytes[i] = (byte) (n & 0xFF);
        }
        String returnStr = "";
        if (StringUtils.isBlank(charsetName)) {
            charsetName = "UTF-8";
        }

        // 指定的 charset 解码指定的 byte 数组，构造一个新的 String
        // utf-8中文字符占三个字节，GB18030兼容GBK兼容GB2312中文字符占两个字节，ISO8859-1是拉丁字符（ASCII字符）占一个字节
        try {
            returnStr = new String(bytes, charsetName);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        // charset还有utf-8,gbk随需求改变
        return returnStr;
    }

    /**
     * 字符串转换为16进制字符串，默认编码格式："utf-8"
     *
     * @param str
     * @return
     */
    public static String str2HexStr(String str) {
        return str2HexStr(str, "UTF-8");
    }

    /**
     * 字符串转换为16进制字符串
     *
     * @param str
     * @param charsetName 用于编码 String 的 Charset
     */
    public static String str2HexStr(String str, String charsetName) {
        byte[] bytes = new byte[0];
        String hexString = "0123456789abcdef";

        if (StringUtils.isBlank(charsetName)) {
            charsetName = "UTF-8";
        }
        try {
            bytes = str.getBytes(charsetName);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        StringBuilder sb = new StringBuilder(bytes.length * 2);
        // 将字节数组中每个字节拆解成2位16进制整数
        for (int i = 0; i < bytes.length; i++) {
            sb.append(hexString.charAt((bytes[i] & 0xf0) >> 4));
            sb.append(hexString.charAt((bytes[i] & 0x0f)));
        }
        return sb.toString().toUpperCase();
    }

    /**
     * 将byte数组按指定字符集转换成字符串
     *
     * @param bytes       字节数组
     * @param charsetName 字符集名称
     * @return
     */
    public static String bytes2Str(byte[] bytes, String charsetName) {
        return new String(bytes, Charset.forName(charsetName));
    }

    /**
     * 将byte数组按UTF-8转换成字符串
     *
     * @param bytes 字节数组
     * @return
     */
    public static String bytes2Str(byte[] bytes) {
        return bytes2Str(bytes, "UTF-8");
    }

    /**
     * 字符串转byte[]，用字符串本身的编码
     *
     * @param stringData 字符串
     * @return 字节数组
     */
    public static byte[] str2Bytes(String stringData) {
        String charsetName = getEncode(stringData);
        return str2Bytes(stringData, charsetName);
    }

    /**
     * 字符串转byte[]，用指定的编码
     *
     * @param stringData  字符串
     * @param charsetName 编码名称，没有的话就用 UTF-8
     * @return 字节数组
     */
    public static byte[] str2Bytes(String stringData, String charsetName) {
        if (StringUtils.isBlank(charsetName)) {
            charsetName = "UTF-8";
        }
        return stringData.getBytes(Charset.forName(charsetName));
    }

    /**
     * 替换字符串模板
     *
     * @param tpl    字符串模板
     * @param params 参数对象
     * @return 替换后的字符串
     */
    public static String buildTplStr(String tpl, JSONObject params) {
        String str = tpl;

        for (Map.Entry<String, Object> item : params.getInnerMap().entrySet()) {
            Object value = item.getValue();
            String valueStr = "";
            if (value != null) {
                valueStr = String.valueOf(value);
            }

            str = str.replace("${" + item.getKey() + "}", valueStr);
        }

        return str;
    }


    /**
     * 判断一个对象是否是数字，或者是否能转换成数字
     *
     * @param obj 对象
     * @return 是数字或者能转成数字时，返回true
     */
    public boolean isNumber(Object obj) {
        if (obj instanceof Number) {
            return true;
        } else {
            try {
                Double.parseDouble(String.valueOf(obj));
                return true;
            } catch (Exception e) {
                return false;
            }
        }
    }

    /**
     * 生成指定长度的随机字符串
     *
     * @param length 长度
     * @return
     */
    public static String getRandomString(int length) {
        String str = "0123456789";
//        String str = "0123456789abcdefg";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(str.length());
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }


    /**
     * 将用splitter分隔的字符串，将其中重复的项删除，空白项删除，再转回字符串
     *
     * @param str
     * @param splitter
     * @return
     */
    public static String removeDuplicate(String str,String splitter){
        if(StringUtils.isBlank(str)){
            return "";
        }
        String[] strArr=StringUtils.split(str,splitter);
        List<String> list=Arrays.asList(strArr);
        List<String> res=removeDuplicate(list);
        return StringUtils.join(res,splitter);
    }

    private static List<String> removeDuplicate(List<String> list) {
        HashSet<String> set = new HashSet<String>(list.size());
        List<String> result = new ArrayList<String>(list.size());
        for (String str : list) {
            str=str.trim().toLowerCase();
            if (StringUtils.isNotBlank(str) && set.add(str)) {
                result.add(str);
            }
        }
        return result;
    }

    public static int double2int(double x){
        return Integer.parseInt(StringUtils.substringBefore(x+"","."));
    }
}
